package com.ssy.lingxi.purchase.serviceimpl.bidding;

import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.rabbitMQ.constants.MessageConstants;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.feign.SystemMessageControllerFeign;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.purchase.api.common.OrderConstant;
import com.ssy.lingxi.purchase.api.common.PurchaseInquiryConstant;
import com.ssy.lingxi.purchase.api.dto.request.BaseAllRequest;
import com.ssy.lingxi.purchase.api.dto.request.BaseDetailsRequest;
import com.ssy.lingxi.purchase.api.dto.request.BaseExamineRequest;
import com.ssy.lingxi.purchase.api.dto.request.bidding.BiddingListRequest;
import com.ssy.lingxi.purchase.api.dto.request.bidding.BiddingProductRequest;
import com.ssy.lingxi.purchase.api.dto.response.CountryAreaResponse;
import com.ssy.lingxi.purchase.api.dto.response.bidding.BiddingDetailsResponse;
import com.ssy.lingxi.purchase.api.dto.response.bidding.BiddingListResponse;
import com.ssy.lingxi.purchase.api.dto.response.bidding.BiddingMemberResponse;
import com.ssy.lingxi.purchase.api.enums.bidding.BiddingExternalWorkStateEnum;
import com.ssy.lingxi.purchase.api.enums.bidding.BiddingListEnum;
import com.ssy.lingxi.purchase.config.rabbitmq.OrderRbbitMqRequest;
import com.ssy.lingxi.purchase.config.rabbitmq.provider.RabbitMQProvider;
import com.ssy.lingxi.purchase.entity.bidding.Bidding;
import com.ssy.lingxi.purchase.entity.bidding.BiddingDemandMember;
import com.ssy.lingxi.purchase.entity.bidding.BiddingProduct;
import com.ssy.lingxi.purchase.repository.bidding.BiddingDemandMemberRepository;
import com.ssy.lingxi.purchase.repository.bidding.BiddingProductRepository;
import com.ssy.lingxi.purchase.repository.bidding.BiddingRepository;
import com.ssy.lingxi.purchase.service.bidding.PlatformBiddingService;
import com.ssy.lingxi.purchase.serviceimpl.BaseBiddingService;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 平台后台采购竞价审核
 *
 * @author wrc
 * @date 2021/3/23
 */
@Slf4j
@Service
public class PlatformBiddingServiceImpl extends BaseBiddingService implements PlatformBiddingService {

    @Resource
    BiddingRepository biddingRepository;
    @Resource
    RabbitMQProvider rabbitMQProvider;
    @Resource
    BiddingDemandMemberRepository biddingDemandMemberRepository;
    @Resource
    BiddingProductRepository biddingProductRepository;
    @Resource
    SystemMessageControllerFeign systemMessageControllerFeign;

    /**
     * 采购竞价单查询
     */
    @Override
    public Wrapper<PageData<BiddingListResponse>> biddingList(BiddingListRequest request, UserLoginCacheDTO sysUser) {
        return getQuery(request, BiddingListEnum.PLATFORM_PURCHASE_BIDDING_QUERY.getType());
    }


    /**
     * 采购询价-采购需求单详情
     */
    @Override
    public Wrapper<BiddingDetailsResponse> biddingDetails(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        BiddingDetailsResponse response = new BiddingDetailsResponse();
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        BeanUtils.copyProperties(bidding, response);
        response.setExternalStateName(BiddingExternalWorkStateEnum.getName(bidding.getExternalState()));
        Long id = bidding.getId();
        //查询采购竞价单物料信息列表
        response.setMateriels(getMateriels(id));
        //查询会员信息
        if (PurchaseInquiryConstant.type.SYSTEM_MATCHING.equals(bidding.getType()) || PurchaseInquiryConstant.type.INVITATION.equals(bidding.getType())) {
            response.setMembers(getBiddingMembers(id));
        }
        response.setAreas(bidding.getAreas().stream().map(temp -> {
            CountryAreaResponse countryArea = new CountryAreaResponse();
            BeanUtils.copyProperties(temp, countryArea);
            return countryArea;
        }).collect(Collectors.toList()));
        //查询采购竞价单内部流程记录
        response.setInteriorLogs(getBiddingInteriorLog(id));
        //查询采购竞价单内部流程状态图
        response.setInteriorLogStates(getLogStateInterior( ProcessEnum.PURCHASE_BIDDING_INTERIOR.getCode(), bidding.getInteriorNextStep()));
        //查询采购竞价单外部流程记录
        response.setExternalLogs(getExternalLog(id));
        //查询采购竞价单外部流程状态图
        response.setExternalLogStates(getLogStateExternal(ProcessEnum.PURCHASE_BIDDING_EXTERNAL.getCode(), bidding.getExternalNextStep(),bidding.getOnLineBidding().getMemberRoleId(),bidding.getCreateMemberRoleId()));
        //审核竞价结果内部流转状态图
        response.setExamineInteriorLogStates(getLogStateInterior(ProcessEnum.PURCHASE_BIDDING_EXAMINE_INTERIOR.getCode(), bidding.getInteriorNextStep()));
        //查询报名信息
        response.setSginUpInfos(getSginUpInfo(id));
        // 授标结果
        response.setAwardsFruit(getAwardsFruits(id));
        //查看竞价过程
        response.setAwardProcess(getAwardProcess(id));
        return Wrapper.success(response);
    }


    /**
     * 待审核采购竞价单查询
     */
    @Override
    public Wrapper<PageData<BiddingListResponse>> examineBidding(BiddingListRequest request, UserLoginCacheDTO sysUser) {
        return getQuery(request, BiddingListEnum.PLATFORM_PURCHASE_BIDDING_LIST.getType());
    }

    /**
     * 审核采购竞价单
     * todo 目前平台审核已经废弃
     */
    @Transactional
    @Override
    public Wrapper ecamine(BaseExamineRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding = biddingRepository.findById(request.getId()).orElse(null);
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
//        if (!BiddingExternalWorkStateEnum.STAY_AUDIT_BIDDING.getState().equals(bidding.getExternalState())) {
//            return Wrapper.fail(ResponseCode.PURCHASE_NOT_AUDIT);
//        }
        boolean isAdopt = OrderConstant.Auditing.PASS == request.getState();
        //执行外部工作流
        Wrapper<SimpleTaskCompleteVO> externalTaskResult = executeWork(bidding.getCreateMemberId(), bidding.getCreateMemberRoleId(), request.getId(), ProcessEnum.PURCHASE_BIDDING_EXTERNAL.getCode(), bidding.getExternalNextStep(), bidding.getExternalTaskId(), request.getState());
        if (ResponseCode.SUCCESS.getCode() != externalTaskResult.getCode()) {
            return externalTaskResult;
        }
        bidding.setExternalTaskId(externalTaskResult.getData().getTaskId());
        bidding.setExternalState(externalTaskResult.getData().getStatus());
        bidding.setExternalNextStep(externalTaskResult.getData().getStep());
//        saveExternalLog(sysUser, "审核采购竞价单", externalTaskResult.getData().getStatus(), bidding.getId(), null, isAdopt ? "同意" : request.getAuditOpinion());
        biddingRepository.saveAndFlush(bidding);
        log.info("用户后台审核竞价单报名:{}", bidding.getId());
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                // 推送消息开始报名
//                sendRabbitMq(bidding);
            }
        });

        if (isAdopt) {
            sendSystemMessageBidding(bidding, MessageTemplateCode.purchase_bidding_audit_register);
        } else {
            sendSystemMessageBidding(bidding, MessageTemplateCode.purchase_bidding_wait_audit);
        }

        return Wrapper.success();
    }

    /**
     * 发送延时队列到 开始报名-待报名
     */
    public void sendRabbitMq(Bidding bidding) {
        //发送MQ定时处理报名时间业务
        OrderRbbitMqRequest rbbitMqRequest = new OrderRbbitMqRequest();
        rbbitMqRequest.setId(bidding.getId());
        rbbitMqRequest.setMemberId(bidding.getCreateMemberId());
        rbbitMqRequest.setMemberRoleId(bidding.getCreateMemberRoleId());
        rbbitMqRequest.setExpirationTime(bidding.getEndSignUp());
        rabbitMQProvider.sendDelayMessage(rbbitMqRequest, MessageConstants.PURCHASE_BIDDING_DELAY_EXCHANGE, MessageConstants.PURCHASE_BIDDING_DELAY_KEY, 2L);
    }

    /**
     * 审核采购竞价单批量
     * todo 目前平台审核已经废弃
     */
    @Transactional
    @Override
    public Wrapper examineBatch(BaseAllRequest request, UserLoginCacheDTO sysUser) {
        List<Bidding> biddings = biddingRepository.findAllById(request.getIds());
        if (CollectionUtils.isEmpty(biddings)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        for (Bidding bidding : biddings) {
//            if (!BiddingExternalWorkStateEnum.STAY_AUDIT_BIDDING.getState().equals(bidding.getExternalState())) {
//                return Wrapper.fail(ResponseCode.PURCHASE_NOT_AUDIT);
//            }
            //执行外部工作流
            Wrapper<SimpleTaskCompleteVO> externalTaskResult = executeWork(bidding.getCreateMemberId(), bidding.getCreateMemberRoleId(), bidding.getId(), ProcessEnum.PURCHASE_BIDDING_EXTERNAL.getCode(), bidding.getExternalNextStep(), bidding.getExternalTaskId(), OrderConstant.State.START);
            if (ResponseCode.SUCCESS.getCode() != externalTaskResult.getCode()) {
                return externalTaskResult;
            }
            bidding.setExternalTaskId(externalTaskResult.getData().getTaskId());
            bidding.setExternalState(externalTaskResult.getData().getStatus());
            bidding.setExternalNextStep(externalTaskResult.getData().getStep());
//            saveExternalLog(sysUser, "审核采购竞价单", externalTaskResult.getData().getStatus(), bidding.getId(), null, "同意");
            biddingRepository.saveAndFlush(bidding);
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    log.info("审核采购竞价单>准备添加延时队列 BiddingId:{}", bidding.getId());
                    // 推送消息开始报名
                    sendRabbitMq(bidding);
                    log.info("审核采购竞价单>添加延时队列完成 BiddingId:{}", bidding.getId());
                }
            });
        }
        return Wrapper.success();
    }


    /**
     * 需求对接会员列表分页查询
     */
    @Override
    public Wrapper<PageData<BiddingMemberResponse>> memberPage(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        Long id = bidding.getId();
        Page<BiddingDemandMember> biddingMembers = biddingDemandMemberRepository.findAllByBiddingId(id, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("id").ascending()));
        long count = biddingMembers.getTotalElements();
        if (0 == count) {
            return Wrapper.success(new PageData<>(count, new ArrayList<>()));
        }
        List<BiddingMemberResponse> biddingMemberResponses = biddingMembers.stream().map(temp -> {
            BiddingMemberResponse biddingMember = new BiddingMemberResponse();
            BeanUtils.copyProperties(temp, biddingMember);
            return biddingMember;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(biddingMembers.getTotalElements(), biddingMemberResponses));
    }

    /**
     * 采购物料分页查询
     */
    @Override
    public Wrapper<PageData<BiddingProductRequest>> materielPage(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        Long id = bidding.getId();
        Page<BiddingProduct> biddingProducts = biddingProductRepository.findAllByBiddingId(id, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("id").ascending()));
        long count = biddingProducts.getTotalElements();
        if (0 == count) {
            return Wrapper.success(new PageData<>(count, new ArrayList<>()));
        }
        List<BiddingProductRequest> collect = biddingProducts.getContent().stream().map(temp -> {
            BiddingProductRequest response = new BiddingProductRequest();
            BeanUtils.copyProperties(temp, response);
            response.setItemNo(temp.getItemNo());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(biddingProducts.getTotalElements(), collect));
    }
    /**
     * 根据不同类型查询采购竞价单列表 queryType：
     */
    public Wrapper<PageData<BiddingListResponse>> getQuery(BiddingListRequest request, Integer queryType) {
        List<BiddingListResponse> responses = new ArrayList<>();
        Specification<Bidding> biddingQuery = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.hasLength(request.getMemberName()))
                predicates.add(criteriaBuilder.like(root.get("memberName"), "%" + request.getMemberName() + "%"));
            if (null != request.getStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), request.getStartTime()));
            }
            if (null != request.getEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), request.getEndTime()));
            }
            if (StringUtils.hasLength(request.getDetails())) {
                predicates.add(criteriaBuilder.like(root.get("details"), "%" + request.getDetails() + "%"));
            }
            if (StringUtils.hasLength(request.getBiddingNo())) {
                predicates.add(criteriaBuilder.like(root.get("biddingNo"), "%" + request.getBiddingNo() + "%"));
            }
            if (null != request.getExternalState()) {
                predicates.add(criteriaBuilder.equal(root.get("externalState"), request.getExternalState()));
            }
//            if (BiddingListEnum.PLATFORM_PURCHASE_BIDDING_LIST.getType().equals(queryType)) {
//                predicates.add(criteriaBuilder.equal(root.get("externalState"), BiddingExternalWorkStateEnum.STAY_AUDIT_BIDDING.getState()));
//            }
            if (BiddingListEnum.PLATFORM_PURCHASE_BIDDING_QUERY.getType().equals(queryType)&&null!=request.getExternalState()) {
                predicates.add(criteriaBuilder.equal(root.get("externalState"), request.getExternalState()));
            }
            Predicate[] predicate = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(predicate));
        };
        Page<Bidding> biddingS = biddingRepository.findAll(biddingQuery, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("createTime").descending()));
        if (0 < biddingS.getTotalElements()) {
            responses = biddingS.getContent().stream().map(temp -> {
                BiddingListResponse response = new BiddingListResponse();
                response.setCreateTime(temp.getCreateTime());
                response.setId(temp.getId());
                response.setExternalStateName(BiddingExternalWorkStateEnum.getName(temp.getExternalState()));
                response.setExternalState(temp.getExternalState());
                response.setDetails(temp.getDetails());
                response.setBiddingNo(temp.getBiddingNo());
                response.setCreateTime(temp.getCreateTime());
                response.setBiddingStartTime(temp.getBiddingStartTime());
                response.setCreateMemberName(temp.getCreateMemberName());
                response.setCreateMemberId(temp.getCreateMemberId());
                response.setCreateMemberRoleId(temp.getCreateMemberRoleId());
                response.setBiddingEndTime(temp.getBiddingEndTime());
                return response;
            }).collect(Collectors.toList());
        }
        return Wrapper.success(new PageData<>(biddingS.getTotalElements(), responses));
    }

    /**
     * 发消息
     */
    @Async
    public void sendSystemMessageBidding(Bidding bidding, String name) {
        try {
            SystemMessageRequest request = new SystemMessageRequest();
            request.setMemberId(bidding.getCreateMemberId());
            request.setRoleId(bidding.getCreateMemberRoleId());
            request.setMessageNotice(name);
            request.setParams(Arrays.asList(bidding.getBiddingNo(), bidding.getDetails()));
            systemMessageControllerFeign.sendSystemMessage(request);
        } catch (Exception e) {
            log.error("发送竞价单通知消息异常", e);
        }
    }
}
